package com.zlx.mall.biz.access.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zlx.mall.base.entity.ScCombo;
import com.zlx.mall.base.entity.ScUser;
import com.zlx.mall.base.service.IScComboService;
import com.zlx.mall.base.service.IScUserService;
import com.zlx.mall.basic.common.constant.PromptConstants;
import com.zlx.mall.basic.common.constant.RedisKeyConstant;
import com.zlx.mall.basic.common.enums.NotDeteteEnum;
import com.zlx.mall.basic.common.exception.IllegalBizArgumentException;
import com.zlx.mall.basic.common.exception.IllegalBizStatusException;
import com.zlx.mall.basic.mask.DataMaskHandler;
import com.zlx.mall.basic.resource.IResourceService;
import com.zlx.mall.basic.util.JwtUtils;
import com.zlx.mall.basic.web.model.BaseRequest;
import com.zlx.mall.basic.web.model.BaseResponse;
import com.zlx.mall.biz.access.enums.SendSwitchEnum;
import com.zlx.mall.biz.access.model.LoginRequest;
import com.zlx.mall.biz.access.model.LoginResponse;
import com.zlx.mall.biz.access.service.IUserLoginService;
import com.zlx.mall.biz.resource.BasicResourceEnum;
import com.zlx.mall.integration.sms.ISmsIntegration;
import com.zlx.mall.integration.sms.constant.JuheSmsConstants;
import com.zlx.mall.integration.sms.model.JuheSmsParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @Author xiatian
 * @Date 2024/5/25 星期六 10:44
 * @注释
 */
@Slf4j
@Service
public class UserLoginServiceImpl implements IUserLoginService {
    @Autowired
    private IScUserService scUserService;
    @Autowired
    private DataMaskHandler dataMaskHandler;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    IResourceService resourceService;
    @Autowired
    private IScComboService scComboService;

    @Resource
    private WxMaService wxMaService;
    /**
     * token过期时间：默认24小时
     */
    @Value("${sxtx.app.biz.token.expire:30}")
    private Integer tokenExpire;
    /**
     * 验证码超时时间 单位秒
     */
    private static final long CODE_TIMEOUT = 10 * 60L;
    /**
     * 每分钟多少秒
     */
    private static final long MIN_SECONDS = 60L;
    @Autowired
    private ISmsIntegration iSmsIntegration;

    @Override
    public String loginVerify(LoginRequest request) {
        String mobile = request.getMobile();
        ScUser user = Optional.ofNullable(scUserService.selectByMobile(mobile)).orElseThrow(() -> new IllegalBizArgumentException("用户不存在,请联系工作人员"));

        //检查用户今天发送验证码次数
        Integer maxCount = resourceService.get(BasicResourceEnum.USER_SMS_CODE_MAX_COUNT, Integer.class, 20);
        int sendCount = (int) Optional.ofNullable(redisTemplate.opsForValue().get(RedisKeyConstant.CACHE_KEY_USER_CODE_SMS_LOGIN_COUNT+ mobile)).orElse(0);
        if (sendCount > maxCount) {
            throw new IllegalBizStatusException(PromptConstants.USER_SMS_VERIFY_OVER_LIMIT_PROMPT);
        }
        String redisKey = RedisKeyConstant.CACHE_KEY_USER_CODE_SMS_LOGIN+ mobile;
        //检查是否存在已发送的短信，并且时间未超过60s
        long expire = redisTemplate.getExpire(redisKey);
        if (CODE_TIMEOUT - expire < MIN_SECONDS) {
            throw new IllegalBizStatusException(String.format(PromptConstants.USER_SMS_VERIFY_FREQUENTLY_PROMPT, (MIN_SECONDS - CODE_TIMEOUT + expire)));
        }
        String verifyCode;
        String sendSwitch = resourceService.get(BasicResourceEnum.SMS_VERIFICATION_CODE_SWITCH, String.class, SendSwitchEnum.OPEN.getCode());
        String loginWhiteList = resourceService.get(BasicResourceEnum.LOGIN_WHITE_LIST, String.class, "");
        if(sendSwitch.equals(SendSwitchEnum.CLOSE.getCode()) || StrUtil.contains(loginWhiteList,mobile)){
            verifyCode = "888888";
        }else {
            //发送短信验证码，记录发送次数到Redis
            verifyCode = RandomUtil.randomNumbers(6);
            JuheSmsParam JhParam = new JuheSmsParam(mobile, JuheSmsConstants.VERIFY_CODE_TPL_ID, "#code#="+verifyCode);
            iSmsIntegration.sendSingleSms(JhParam);

        }
        redisTemplate.opsForValue().set(redisKey, verifyCode, CODE_TIMEOUT, TimeUnit.SECONDS);
        long expireTime = (DateUtil.endOfDay(new Date()).getTime() - System.currentTimeMillis()) / 1000;
        redisTemplate.expire(RedisKeyConstant.CACHE_KEY_USER_CODE_SMS_LOGIN_COUNT+mobile, expireTime, TimeUnit.SECONDS);
        return String.format(PromptConstants.USER_GET_SMS_VERIFY_CODE_PROMPT, mobile.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
    }

    @Override
    public BaseResponse login(LoginRequest request) {
        String mobile = request.getMobile();
        String verifyCode = request.getVerifyCode();
        if (StrUtil.isEmpty(mobile) || StrUtil.isEmpty(verifyCode)) {
            throw new IllegalBizStatusException("请输入手机号或短信验证码");
        }

        //校验验证码
        String imgVerifyCode = (String) redisTemplate.opsForValue().get(RedisKeyConstant.CACHE_KEY_USER_CODE_SMS_LOGIN + mobile);
        if (imgVerifyCode == null) {
            throw new IllegalBizStatusException(PromptConstants.USER_IMG_VERIFY_CODE_EXPIRED_PROMPT);
        }
        if (!imgVerifyCode.equals(verifyCode)) {
            throw new IllegalBizStatusException(PromptConstants.USER_IMG_VERIFY_CODE_ERROR_PROMPT);
        }
        ScUser user = Optional.ofNullable(scUserService.selectByMobile(mobile)).orElseThrow(() -> new IllegalBizArgumentException("用户不存在,请联系工作人员"));
        LoginResponse loginResponse = generateUserToken(user.getId(), mobile);
        loginResponse.setProject(user.getProject());
        loginResponse.setHouseType(user.getHouseType());
        loginResponse.setRoomNumber(user.getRoomNumber());
        loginResponse.setName(user.getName());
        loginResponse.setAfterSalesMobile(resourceService.get(BasicResourceEnum.AFTER_SALES_MOBILE, String.class, "13299001000"));
        ScCombo combo = scComboService.getOne(new QueryWrapper<ScCombo>().eq(ScCombo.SELECT_CODE, user.getSelectCode()).eq(ScCombo.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()));
        if (combo != null) {
            loginResponse.setSelectCode( combo.getSelectCode());
            loginResponse.setComboId(combo.getId());
        }
        return BaseResponse.success(loginResponse);
    }

    @Override
    public void logout(BaseRequest request) {
        String token = request.getSystem().getToken();
        if (StrUtil.isNotEmpty(token)) {
            JWT jwt = JwtUtils.parse(token);
            JSONObject payloads = jwt.getPayloads();
            String mobile = payloads.getStr(JwtUtils.PAYLOAD_MOBILE);
            String key = RedisKeyConstant.CACHE_KEY_USER_TOKEN + mobile;
            String redisToken = (String) redisTemplate.opsForValue().get(key);
            if (StringUtils.hasText(redisToken)) {
                redisTemplate.delete(key);
            }
            log.info("{}用户登出成功", mobile);
        }
    }

    @Override
    public String afterSalesMobile() {
        return resourceService.get(BasicResourceEnum.AFTER_SALES_MOBILE, String.class, "13299001000");
    }

    public static void main(String[] args) {
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wxaae1a7726d76c342&secret=30d979634fe2b2cffbaa589e9e6ebc05";

        HttpRequest get = HttpUtil.createGet(url);
        HttpResponse getResponse = get.execute();
        String getResult = getResponse.body();
        getResponse.close();
        JSONObject parseObj = JSONUtil.parseObj(getResult);
        String accessToken = (String) parseObj.get("access_token");

        String mobileUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="+accessToken;
        HttpRequest post = HttpUtil.createPost(mobileUrl);
        post.body("code="+"123456789");
        HttpResponse postResponse = post.execute();
        String postResult = postResponse.body();
        postResponse.close();
        JSONObject jsonObject = JSONUtil.parseObj(postResult);
        log.info("jsonObject={}", jsonObject);
        int errorCode = (int) jsonObject.get("errcode");
        if( errorCode== 0) {
            Object o = jsonObject.get("phone_info");
        }

    }

    @Override
    public LoginResponse loginFast(String code) {

        String mobile = getUserMobile(code);

        ScUser user = Optional.ofNullable(scUserService.selectByMobile(mobile)).orElseThrow(() -> new IllegalBizArgumentException("登录失败,请联系工作人员"));

        LoginResponse loginResponse = generateUserToken(user.getId(), mobile);
        loginResponse.setProject(user.getProject());
        loginResponse.setHouseType(user.getHouseType());
        loginResponse.setRoomNumber(user.getRoomNumber());
        loginResponse.setName(user.getName());
        loginResponse.setAfterSalesMobile(resourceService.get(BasicResourceEnum.AFTER_SALES_MOBILE, String.class, "13299001000"));
        ScCombo combo = scComboService.getOne(new QueryWrapper<ScCombo>().eq(ScCombo.SELECT_CODE, user.getSelectCode()).eq(ScCombo.IS_DELETE, NotDeteteEnum.NOT_DELETE.getCode()));
        if (combo != null) {
            loginResponse.setSelectCode( combo.getSelectCode());
            loginResponse.setComboId(combo.getId());
        }

        return loginResponse;
    }

    private String getUserMobile(String code){
        WxMaPhoneNumberInfo phoneNumberInfo;
        try {
            phoneNumberInfo = wxMaService.getUserService().getNewPhoneNoInfo(code);
            log.info("微信小程序登录：loginCode="+code+",微信用户信息："+ com.alibaba.fastjson.JSONObject.toJSONString(phoneNumberInfo));
        } catch (Exception exception) {
            log.error("通过微信小程序code={}获取手机号失败！异常信息={}", code, exception.getMessage());
            throw new IllegalBizArgumentException("微信快捷登录失败");
        }
        return phoneNumberInfo.getPhoneNumber();
    }

    private LoginResponse generateUserToken(Long id, String mobile) {
        String token = JwtUtils.createToken(id, mobile);
        LoginResponse loginResponse = new LoginResponse();
        loginResponse.setUserId(id);
        loginResponse.setMobileMask(dataMaskHandler.maskMobile(mobile));
        loginResponse.setToken(token);
        //缓存token
        String subToken = StrUtil.subBetween(token, ".", ".");
        redisTemplate.opsForValue().set(RedisKeyConstant.CACHE_KEY_USER_TOKEN + mobile, subToken, tokenExpire, TimeUnit.DAYS);
        return loginResponse;
    }
}
